Keep database deploys separate
タイトルの通りデータベースとデプロイを分離すべきという意見
Government Digital Service(イギリスのデジタル庁みたいな)に務める @philandstuff
2018-04
Context
前提
ブラウザやモバイルネイティブアプリケーションで利用するウェブアプリを構築している
デプロイするときはいつでも、誰かがそのアプリを使用している可能性が高い
アプリをダウンタイムなしでデプロイするためのテクニックを採用する
アプリを週に複数回(場合によっては1日に複数回)デプロイする
メンテナンス画面なし
多くのチームは、Continuous Deliveryの本を読んだ後、自動化されたデプロイメントパイプラインを設定する
インクリメンタルなコードの変更がさまざまなテスト段階を経て本番環境に到達するまでの明確で再現性のあるパスがあることを確認している
デプロイメントパイプラインの最終段階では、最新のコードとマイグレーションが単一のデプロイメント段階で本番環境にデプロイされる
ここに問題がある
データベースのマイグレーションは、コードの変更よりも本質的にリスクの高い種類の変更である
データベースの移行に関する問題は、本番環境にデプロイしたときにしか現れないかもしれない。本番環境の問題は、本番でしか起きないことが多い
データベーススキーマの古いバージョンがまだアクティブである間に、アクティブなユーザーがアプリの新しいバージョンにアクセスする(またはその逆もあります)
ohbarye.icon migrationとdeployを直列にやっても並列にやってもどの順でやってもありうる
ダウンタイムを回避する方法でデプロイを行っていますが、どんな方法で行うにしても、古いコードと新しいコードに同時にリクエストが来る可能性がある
開発とテストはデプロイ中ではなくデプロイとデプロイの間に実行されるため、コードはスキーマの後方互換性や前方互換性のテストを受けないことが多い
開発者がコードやスキーマをアトミックに変更するコミットを作成することの危険性を理解していない環境では、デプロイ中にシステムを使用しようとしたときだけ問題が発生する
最後の問題
データベースの変更はコードの変更よりもロールバックが難しい
多くの場合、rollback migration scriptは利用できない
rollbackコードを書いたとしても、forward (up) migration scriptに問題があった場合はそもそも信用できないかもしれない
rollbackが実行されていたとしても、すでに取り返しのつかないほどのデータを失っているかもしれない
絶対ではない
コードの変更もデータを失う可能性があるがそのリスクプロファイルは低くなる
単純なWebリクエストハンドラよりも、UPDATE文を使って大規模にデータを失う方が容易
Decision
データベースの変更をコードの変更と同じステップでデプロイしない
単一のデプロイパイプラインステージでは、コードとデータの両方をデプロイしてはいけないということを意味する 各デプロイはスモークテストされ、データ変更のないコード変更が何も壊れないことをテストし、同様にコード変更のないデータ変更も問題ないことをテストします この手法は、デプロイプロセスのすべてのステップで、データベーススキーマに対するコードの後方互換性と前方互換性を検証していることを意味する
実現する方法はいくつかある
ビルドパラメータに基づいてコードのデプロイとマイグレーションを分ける
コード用とマイグレーション用に全く別のデプロイメント パイプラインを用意する
データベースが外部サービスであるかのように依存する
データベースのデプロイメントを週次などにコントロールもできる
単にリリースにデータベースの変更かコードの変更のどちらかしか含めないようにする
コードレビューやリリース管理に依存して違反を検出するという規則を設ける
非常にローテクな方法は、
たとえコードとデータベースのデプロイメントを分離しても、重要なことがいくつかある
データベーススキーマは、手作業で作成したものではなく、ソース管理された定義から構築されるべきです。
データベーススキーマは、移行ツールを使用して管理する必要があります。
データベーススキーマは、開発環境とテスト環境で変更をテストしてから本番環境で実行するというデプロイメントパイプラインを使用してデプロイされなければなりません。
Consequence
開発者はこの環境に適応し、以下の両方を理解しなければならない
データベースの変更はリスクが高いと考えられていること
データベースの変更を導入したい場合、ロールアウトをどのようにオーケストレーションするかを検討しなければならないこと
典型的なシナリオでは、3つのステップを踏むことになる
1つ目は、新しいスキーマが到着したときにサポートできる新しいアプリをリリースすること
2つ目は、データベースの移行をデプロイすること
3つ目は、古いスキーマとの互換性のために古いコードを削除した新しいアプリをリリースすること
めんどうでも開発者がすべきことである
そのコードが本番環境にデプロイされたときにユーザーに問題を引き起こすからです
実際にはこの段階的なロールアウトを行わないか、忘れてしまうことがあります
新しいシステムでは、前方互換性のあるコード変更を書かなければ、コードのデプロイはスモークテストに失敗することになります。その結果、コードとスキーマのバージョンの不一致による本番環境での失敗は少なくなるはず
データベースの変更コストが高くなる
これは設計上のものですが、データベース内の修正の方がより正しいのに、コード内に修正を書いた方が簡単だからといって、コード内に修正を書いてしまうというような倒錯した行動のリスクがある
この変更により、データベースの移行の危険性のすべてが解決されるわけではない
新しい列を追加するために大きなテーブルのすべてのレコードを更新しようとするのは、やはり時間がかかります
A brief survey of other people’s views
InfoQ
データベースの変更はデプロイメントパイプラインに含めるべきと主張
スキーマの変更を利用したコードのデプロイからデプロイを切り離すことは、Etsyでは非常に大きな利点があった
人々は彼に「1日に50回デプロイするとしたら、どうやってデータベースを1日に50回変更するのか」と質問し、彼の答えは「まあ、しない」だそうです。
flickrでは、隔週の火曜日にデータベースの変更を行うためにメンテナンスモードにしていた(ゼロダウンタイムではない)